/*
 * ESP32 Bluetooth Audio Receiver - Core Application Implementation
 * 
 * Copyright (c) 2025 lianggumei
 * 
 * SPDX-License-Identifier: MIT
 */

#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/ringbuf.h"
#include "driver/i2s_std.h"
#include "bt_app_core.h"

static const char* kTag = "BtAppCore";

// I2S related
static i2s_chan_handle_t tx_chan = NULL;
static RingbufHandle_t ring_buffer = NULL;
static TaskHandle_t i2s_task_handle = NULL;

// I2S task handler function
static void i2s_task_handler(void* arg);

esp_err_t bt_i2s_task_start_up(void) {
    ESP_LOGI(kTag, "Starting I2S task");
    
    // Create ring buffer
    ring_buffer = xRingbufferCreate(16 * 1024, RINGBUF_TYPE_BYTEBUF);
    if (ring_buffer == NULL) {
        ESP_LOGE(kTag, "Failed to create ring buffer");
        return ESP_ERR_NO_MEM;
    }
    
    // Create I2S task
    BaseType_t ret = xTaskCreate(i2s_task_handler, "I2STask", 4096, 
                                NULL, 6, &i2s_task_handle);
    if (ret != pdPASS) {
        ESP_LOGE(kTag, "Failed to create I2S task: %d", ret);
        vRingbufferDelete(ring_buffer);
        ring_buffer = NULL;
        return ESP_FAIL;
    }
    
    ESP_LOGI(kTag, "I2S task started successfully");
    return ESP_OK;
}

size_t write_ringbuf(const uint8_t* data, size_t len) {
    if (ring_buffer == NULL) {
        return 0;
    }
    
    BaseType_t ret = xRingbufferSend(ring_buffer, data, len, 0);
    if (ret != pdTRUE) {
        // 缓冲区满，丢弃数据
        return 0;
    }
    
    return len;
}

static void i2s_task_handler(void* arg) {
    ESP_LOGI(kTag, "I2S task started running");
    
    uint8_t* data = NULL;
    size_t item_size = 0;
    size_t bytes_written = 0;
    const size_t max_item_size = 4096;
    
    while (true) {
        // Read data from ring buffer
        data = (uint8_t*)xRingbufferReceiveUpTo(ring_buffer, &item_size, 
                                               pdMS_TO_TICKS(50), max_item_size);
        
        if (data != NULL && item_size > 0) {
            // Write to I2S
            esp_err_t ret = i2s_channel_write(tx_chan, data, item_size, 
                                             &bytes_written, pdMS_TO_TICKS(200));
            if (ret != ESP_OK) {
                ESP_LOGE(kTag, "I2S write failed: %s", esp_err_to_name(ret));
            }
            
            // Release buffer
            vRingbufferReturnItem(ring_buffer, data);
        } else {
            // No data, wait briefly
            vTaskDelay(pdMS_TO_TICKS(10));
        }
    }
}

// Install I2S driver
void bt_i2s_driver_install(void) {
    ESP_LOGI(kTag, "Installing I2S driver");
    
    // I2S channel configuration
    i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_0, I2S_ROLE_MASTER);
    chan_cfg.auto_clear = true;
    chan_cfg.dma_desc_num = 4;
    chan_cfg.dma_frame_num = 256;
    
    // Create I2S channel
    esp_err_t ret = i2s_new_channel(&chan_cfg, &tx_chan, NULL);
    if (ret != ESP_OK) {
        ESP_LOGE(kTag, "Failed to create I2S channel: %s", esp_err_to_name(ret));
        return;
    }
    
    // I2S standard configuration
    i2s_std_config_t std_cfg = {
        .clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(44100),
        .slot_cfg = {
            .data_bit_width = I2S_DATA_BIT_WIDTH_16BIT,
            .slot_bit_width = I2S_SLOT_BIT_WIDTH_16BIT,
            .slot_mode = I2S_SLOT_MODE_STEREO,
            .slot_mask = I2S_STD_SLOT_BOTH,
            .ws_width = 16,
            .ws_pol = false,
            .bit_shift = false,
            .msb_right = false,
        },
        .gpio_cfg = {
            .mclk = I2S_GPIO_UNUSED,
            .bclk = (gpio_num_t)CONFIG_EXAMPLE_I2S_BCK_PIN,
            .ws = (gpio_num_t)CONFIG_EXAMPLE_I2S_LRCK_PIN,
            .dout = (gpio_num_t)CONFIG_EXAMPLE_I2S_DATA_PIN,
            .din = I2S_GPIO_UNUSED,
            .invert_flags = {
                .mclk_inv = false,
                .bclk_inv = false,
                .ws_inv = false,
            },
        },
    };
    
    // Initialize I2S standard mode
    ret = i2s_channel_init_std_mode(tx_chan, &std_cfg);
    if (ret != ESP_OK) {
        ESP_LOGE(kTag, "Failed to initialize I2S standard mode: %s", esp_err_to_name(ret));
        i2s_del_channel(tx_chan);
        tx_chan = NULL;
        return;
    }
    
    // Enable I2S channel
    ret = i2s_channel_enable(tx_chan);
    if (ret != ESP_OK) {
        ESP_LOGE(kTag, "Failed to enable I2S channel: %s", esp_err_to_name(ret));
        i2s_del_channel(tx_chan);
        tx_chan = NULL;
        return;
    }
    
    ESP_LOGI(kTag, "I2S driver installed successfully");
}
